package org.cjstudio.holypoopsgrs.test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.cjstudio.holypoopsgrs.model.UserProfile;
import org.cjstudio.holypoopsgrs.model.UserRecord;
import org.cjstudio.holypoopsgrs.server.UserProfileRepository;
import org.cjstudio.holypoopsgrs_interface.game.model.HolyPoopsLeaderboard;
import org.cjstudio.holypoopsgrs_interface.game.model.HolyPoopsLeaderboardEntry;
import org.cjstudio.holypoopsgrs_interface.game.model.HolyPoopsPersonalRecord;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;

public class UserProfileTest2 {

	private static final String UserUDID = "CORYJIN";
	private static final String BaseUDID = "udid";

	private final LocalServiceTestHelper helper = new LocalServiceTestHelper(
			new LocalDatastoreServiceTestConfig());

	private final UserProfileRepository userProfileRepository = new UserProfileRepository();

	@Before
	public void setUp() {
		helper.setUp();

		Date date = new Date();

		UserProfile profile = new UserProfile();
		profile.udid = UserUDID;
		profile.name = "user1";
		profile.highest = 100;
		profile.rank = 1;
		profile.highestDate = date;
		profile.message = "YAY!";
		profile.updateDate = date;
		profile.numOfRecords = 1;
		profile.averageScore = 100;

		List<UserRecord> records = new ArrayList<UserRecord>();
		for(int i=0; i<10; i++) {
			UserRecord record = new UserRecord();
			record.score = 10 * (10 - (i + 1));
			record.scoreDate = new Date();

			records.add(record);
		}
		profile.topTenRecords = records;

		userProfileRepository.create(profile);

		UserProfile storedProfile = userProfileRepository.retrieve(UserUDID);

		Assert.assertEquals(profile.udid, storedProfile.udid);
		Assert.assertEquals(profile.name, storedProfile.name);
		Assert.assertEquals(profile.highest, storedProfile.highest);
		Assert.assertEquals(profile.rank, storedProfile.rank);
		Assert.assertEquals(profile.highestDate, storedProfile.highestDate);
		Assert.assertEquals(profile.message, storedProfile.message);
		Assert.assertEquals(profile.updateDate, storedProfile.updateDate);
		Assert.assertEquals(profile.numOfRecords, storedProfile.numOfRecords);
		Assert.assertEquals((int)profile.averageScore, (int)storedProfile.averageScore);
		Assert.assertNotNull(storedProfile.topTenRecords);
		Assert.assertEquals(profile.topTenRecords.size(), storedProfile.topTenRecords.size());

		for(int i=0; i<profile.topTenRecords.size(); i++) {
			Assert.assertEquals(profile.topTenRecords.get(i).score, storedProfile.topTenRecords.get(i).score);
			Assert.assertEquals(profile.topTenRecords.get(i).scoreDate, storedProfile.topTenRecords.get(i).scoreDate);
		}
	}

	@After
	public void tearDown() {
		helper.tearDown();
	}

	//	@Test
	public void testLeaderboard() {
		String type = "daily";
		Integer limit = 10;
		String key = "CORYJIN";

		/* Log */
		System.out.println("HolyPoopsServlet: holypoops/leaderboard/" + type);
		System.out.println("Type : " + type);
		System.out.println("Limit : " + limit);
		System.out.println("Key : " + key);

		//verify with key
		if(verifyWithKey(key) == false) {
			System.out.println("Return : NULL");
			return;
		}

		//retrieve top ten records
		List<UserProfile> profiles = userProfileRepository.retrieveWithRange(1, 10);
		ArrayList<HolyPoopsLeaderboardEntry> entries = new ArrayList<HolyPoopsLeaderboardEntry>();
		for(UserProfile profile : profiles) {
			entries.add(profile.toEntry());
		}

		HolyPoopsLeaderboard leaderboard = new HolyPoopsLeaderboard();
		leaderboard.entries = entries;
		leaderboard.leaderboardDate = new Date();

		if(type.equals(HolyPoopsLeaderboard.LEADERBOARD_TYPE_DAILY)) {
			leaderboard.type = HolyPoopsLeaderboard.LEADERBOARD_TYPE_DAILY;
		} else if(type.equals(HolyPoopsLeaderboard.LEADERBOARD_TYPE_WEEKLY)) {
			leaderboard.type = HolyPoopsLeaderboard.LEADERBOARD_TYPE_WEEKLY;
		} else if(type.equals(HolyPoopsLeaderboard.LEADERBOARD_TYPE_TOTAL)) {
			leaderboard.type = HolyPoopsLeaderboard.LEADERBOARD_TYPE_TOTAL;
		}

		System.out.println(leaderboard.toString());
	}

	//	@Test
	public void testPersonalRecord() {
		String key = "CORYJIN";

		/* Log */
		System.out.println("HolyPoopsServlet: holypoops/record/" + key);
		System.out.println("Key : " + key);

		//verify with key
		if(verifyWithKey(key) == false) {
			System.out.println("Return : NULL");
			return;
		}

		//retrieve record
		UserProfile profile = userProfileRepository.retrieve(key);

		System.out.println("Return : " + profile.toString());

		HolyPoopsPersonalRecord record = profile.toPersonalRecord();
		return;
	}

	public void testPersonalRecord2() {
		String key = "CORYJIN";
		String name = "Cory Jin";
		Integer score = 100;

		/* Log */
		System.out.println("HolyPoopsServlet: holypoops/record/" + key);
		System.out.println("Key : " + key);
		if(name != null)
			System.out.println("Name : " + name);
		if(score != null)
			System.out.println("Score : " + score);

		//verify with key
		if(verifyWithKey(key) == false) {
			System.out.println("Return : NULL");
			return;
		}

		//retrieve record
		UserProfile profile = userProfileRepository.retrieve(key);

		boolean dirty = false;
		if(name != null) {
			//update name
			profile.name = name;
			dirty = true;
		}

		if(score != null) {
			List<UserRecord> records = profile.topTenRecords;
			if(score >= records.get(records.size()-1).score) {
				// update score
				for(int i=0; i<records.size(); i++) {
					if(records.get(i).score > score) {
						continue;
					} else {
						UserRecord newRecord = new UserRecord();
						newRecord.score = score;
						newRecord.scoreDate = new Date();
						records.add(newRecord);
						records.remove(records.size()-1);
						break;
					}
				}
				dirty = true;
			}
		}

		if(dirty) userProfileRepository.update(profile);

		System.out.println("Return : " + profile.toString());

		HolyPoopsPersonalRecord record = profile.toPersonalRecord();
	}

	public boolean verifyWithKey(String key) {
		return true;
	}


	public void testScoreboard() {
		String key = "CORYJIN";

		/* Log */
		System.out.println("HolyPoopsServlet: holypoops/scoreboard");
		System.out.println("Key : " + key);

		//verify with key
		if(verifyWithKey(key) == false) {
			System.out.println("Return : NULL");
			return;
		}

		//retrieve records
		List<UserProfile> profiles = userProfileRepository.retrieveAll();

		StringBuilder sb = new StringBuilder();
		for(int i=0; i<profiles.size(); i++) {
			sb.append("Profile " + i + "\n");
			sb.append(profiles.get(i).toString());
		}

		String result = sb.toString();

		System.out.println(result);

		return;
	}


	public void createAndRetrieveTestForUserProfile() {
		Date date = new Date();

		UserProfile profile = new UserProfile();
		profile.udid = UserUDID;
		profile.name = "user1";
		profile.highest = 100;
		profile.rank = 1;
		profile.highestDate = date;
		profile.message = "YAY!";
		profile.updateDate = date;
		profile.numOfRecords = 1;
		profile.averageScore = 100;

		List<UserRecord> records = new ArrayList<UserRecord>();
		for(int i=0; i<10; i++) {
			UserRecord record = new UserRecord();
			record.score = 10 * (10 - (i + 1));
			record.scoreDate = new Date();

			records.add(record);
		}
		profile.topTenRecords = records;

		userProfileRepository.create(profile);

		UserProfile storedProfile = userProfileRepository.retrieve(UserUDID);

		Assert.assertEquals(profile.udid, storedProfile.udid);
		Assert.assertEquals(profile.name, storedProfile.name);
		Assert.assertEquals(profile.highest, storedProfile.highest);
		Assert.assertEquals(profile.rank, storedProfile.rank);
		Assert.assertEquals(profile.highestDate, storedProfile.highestDate);
		Assert.assertEquals(profile.message, storedProfile.message);
		Assert.assertEquals(profile.updateDate, storedProfile.updateDate);
		Assert.assertEquals(profile.numOfRecords, storedProfile.numOfRecords);
		Assert.assertEquals((int)profile.averageScore, (int)storedProfile.averageScore);
		Assert.assertNotNull(storedProfile.topTenRecords);
		Assert.assertEquals(profile.topTenRecords.size(), storedProfile.topTenRecords.size());

		for(int i=0; i<profile.topTenRecords.size(); i++) {
			Assert.assertEquals(profile.topTenRecords.get(i).score, storedProfile.topTenRecords.get(i).score);
			Assert.assertEquals(profile.topTenRecords.get(i).scoreDate, storedProfile.topTenRecords.get(i).scoreDate);
		}

	}

	//	@Test
	public void retrieveAndDeleteTestForUserProfile() {
		for(int i=0; i<10; i++) {
			Date date = new Date();

			UserProfile profile = new UserProfile();
			profile.udid = BaseUDID + i;
			profile.name = "user" + i;
			profile.highest = 100 - i * 5;
			profile.rank = 1 + i;
			profile.highestDate = date;
			profile.message = "YAY! I'm " + profile.name;
			profile.updateDate = date;
			profile.numOfRecords = 100 - i*2;
			profile.averageScore = 50 - i*3;

			List<UserRecord> records = new ArrayList<UserRecord>();
			for(int j=0; j<10; j++) {
				UserRecord record = new UserRecord();
				record.score = 10 * (10 - (j + 1)) + j;
				record.scoreDate = new Date();

				records.add(record);
			}
			profile.topTenRecords = records;

			userProfileRepository.create(profile);
		}

		List<UserProfile> profiles = userProfileRepository.retrieveAll();
		Assert.assertNotNull(profiles);

		for(int i=0; i<profiles.size(); i++) {
			Assert.assertEquals(BaseUDID + i, profiles.get(i).udid);
			Assert.assertEquals("user" + i, profiles.get(i).name);
			Assert.assertEquals(100 - i * 5, profiles.get(i).highest);
			Assert.assertEquals(1 + i, profiles.get(i).rank);
			Assert.assertEquals("YAY! I'm " + "user" + i, profiles.get(i).message);
			Assert.assertEquals(100 - i*2, profiles.get(i).numOfRecords);
			Assert.assertEquals((int)50 - i*3, (int)profiles.get(i).averageScore);

			for(int j=0; j<10; j++) {
				List<UserRecord> records = profiles.get(i).topTenRecords;

				Assert.assertEquals(10 * (10 - (j + 1)) + j, records.get(j).score);
			}

			if(i%2 == 0) {
				userProfileRepository.delete(profiles.get(i));
			}
		}
		profiles = userProfileRepository.retrieveAll();
		Assert.assertEquals(5, profiles.size());

		for(int i=0; i<10; i++) {
			if(i%2 == 1) {
				userProfileRepository.delete("udid" + i);				
			}
		}
		profiles = userProfileRepository.retrieveAll();
		Assert.assertEquals(0, profiles.size());

	}

}
